package com.agentframework.core.annotation;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wangjun
 **/
public abstract class AbstractClassPathScanner extends ClassPathBeanDefinitionScanner {

    private final Map<Class<? extends Annotation>, Map<String, BeanDefinition>> scannedBeans = new ConcurrentHashMap<>();

    private final Class<? extends Annotation> annotation;

    public AbstractClassPathScanner(BeanDefinitionRegistry registry, Class<? extends Annotation> annotation) {
        super(registry, false);
        this.annotation = annotation;
    }

    protected void registerFilters() {
        addIncludeFilter(new AnnotationTypeFilter(annotation));

        addExcludeFilter((metadataReader, metadataReaderFactory) -> {
            String className = metadataReader.getClassMetadata().getClassName();
            return className.endsWith("package-info");
        });
    }

    protected abstract void addPropertyValue(BeanDefinition definition);

    @NotNull
    @Override
    protected Set<BeanDefinitionHolder> doScan(@NotNull String... basePackages) {

        // 1. 执行扫描
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

        processBeanDefinitions(beanDefinitions);

        return beanDefinitions;
    }

    protected void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
            addPropertyValue(definition);

            scannedBeans.computeIfAbsent(this.annotation, k -> new HashMap<>()).put(holder.getBeanName(), definition);
        }
    }

    protected boolean hasProperty(Class<?> clazz, String propertyName) {
        String capitalizedName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        try {
            // 检查是否有对应的 getter 方法
            clazz.getMethod("get" + capitalizedName);
            // 检查是否有对应的 setter 方法
            clazz.getMethod("set" + capitalizedName, clazz.getMethod("get" + capitalizedName).getReturnType());
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    public Map<Class<? extends Annotation>, Map<String, BeanDefinition>> getScannedBeans() {
        return scannedBeans;
    }

}
